package com.bangcommunity.bbframe.sdm.aop;

import com.bangcommunity.bbframe.common.base.BaseResult;
import com.bangcommunity.bbframe.common.base.ResultCode;
import com.bangcommunity.bbframe.common.exception.BaseRtmException;
import com.bangcommunity.bbframe.common.utils.ToStringUtil;
import com.bangcommunity.bbframe.common.utils.lang.AnnotationUtils;
import com.bangcommunity.bbframe.common.utils.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * @author huaicheng.thc
 */
public class WrapAspectUtil {
    public static Object doWrapLogException(ProceedingJoinPoint pjp, String keyword, Logger log) throws Throwable {
        long time = System.currentTimeMillis();
        Object[] args = null;
        Method method = null;
        String className = null;
        String methodName = null;
        String argStr = null;
        Object result = null;
        boolean needLog = false;
        try {
            args = pjp.getArgs();
            method = ((MethodSignature) pjp.getSignature()).getMethod();// 拦截的方法
            className = pjp.getTarget().getClass().getSimpleName();// 拦截的类名
            methodName = method.getName();// 拦截的方法名
            SkipLog skipLogAnnotation = AnnotationUtils.findAnnotation(method, SkipLog.class);
            if (null != skipLogAnnotation) {
                return pjp.proceed(args);
            } else {
                skipLogAnnotation = AnnotationUtils.findAnnotation(pjp.getTarget().getClass(), SkipLog.class);
                if (null != skipLogAnnotation) {
                    return pjp.proceed(args);
                }
            }
            RecordLog recordLogAnnotation = AnnotationUtils.findAnnotation(method, RecordLog.class);
            if (null == recordLogAnnotation) {
                recordLogAnnotation = AnnotationUtils.findAnnotation(pjp.getTarget().getClass(), RecordLog.class);
                if (null == recordLogAnnotation) {
                    return pjp.proceed(args);
                }
            }
            needLog = true;
            argStr = StringUtils.join(args, "||");
            log.info("begin {} {} {}: param={}", new Object[] { keyword, className, methodName, argStr });
            result = pjp.proceed(args);
            return result;
        } catch (Exception targetException) {
            log.error("!!!!  {}  {} {} exception: param={}",
                    new Object[] { keyword, className, methodName, argStr, targetException });
            WrapException wrapExceptionAnnotation = AnnotationUtils.findAnnotation(method, WrapException.class);
            if (null != wrapExceptionAnnotation) {
                String message = targetException.getMessage();
                return BaseResult.fail(StringUtils.isNotBlank(message) ? message : "服务调用错误");
            }
            throw targetException;
        } finally {
            if (needLog) {
                log.info("end {} {} {}: param={}, result={}, times={}ms", new Object[] { keyword, className, methodName,
                        argStr, ToStringUtil.reflectionToString(result), System.currentTimeMillis() - time });
            }
        }
    }

    /**
     * 方法 和 类 接口上只要有一个地方配置了注解返回true,否则返回false
     * 
     * @param clazz
     * @param method
     * @param annotationClz
     * @return
     */
    public static <A extends Annotation> boolean hasAnnotation(Class clazz, Method method, Class<A> annotationClz) {
        A annotation = findAnnotation(clazz, method, annotationClz);
        return null != annotation;
    }

    /**
     * 方法 和 类 接口上只要有一个地方配置了注解返回true,否则返回false
     * 
     * @param clazz
     * @param method
     * @param annotationClz
     * @return
     */
    public static <A extends Annotation> A findAnnotation(Class clazz, Method method, Class<A> annotationClz) {
        if (null != method) {
            A annotation = AnnotationUtils.findAnnotation(method, annotationClz);
            if (null != annotation) {
                return annotation;
            } else if (null == annotation && clazz != null) {
                annotation = (A) AnnotationUtils.findAnnotation(clazz, annotationClz);
                if (null != annotation) {
                    return annotation;
                }
            }
        }
        return null;
    }

    public static BaseResult exceptionToBaseResult(Throwable throwable) {
        if (null != throwable) {
            if (throwable instanceof BaseRtmException) {
                BaseRtmException excep = (BaseRtmException) throwable;
                String message = excep.getMessage();
                return BaseResult.fail(StringUtils.isNotBlank(message) ? message : "服务调用错误");
            } else if (throwable instanceof ConstraintViolationException) {
                ConstraintViolationException excep = (ConstraintViolationException) throwable;
                String message = null;
                Set<ConstraintViolation<?>> constraintViolations = excep.getConstraintViolations();
                if (null != constraintViolations) {
                    for (ConstraintViolation cv : constraintViolations) {
                        message = cv.getMessage();
                        break;
                    }
                }
                return BaseResult.fail(StringUtils.isNotBlank(message) ? message : "服务调用错误");
            }
            String message = throwable.getMessage();
            return BaseResult.fail(StringUtils.isNotBlank(message) ? message : "服务调用错误");
        }
        return null;
    }

    public static BaseRtmException exceptionToBaseRtmException(Throwable throwable) {
        if (null != throwable) {
            if (throwable instanceof BaseRtmException) {
                return (BaseRtmException) throwable;
            } else if (throwable instanceof ConstraintViolationException) {
                ConstraintViolationException excep = (ConstraintViolationException) throwable;
                String message = null;
                Set<ConstraintViolation<?>> constraintViolations = excep.getConstraintViolations();
                if (null != constraintViolations) {
                    for (ConstraintViolation cv : constraintViolations) {
                        message = cv.getMessage();
                        break;
                    }
                }
                return new BaseRtmException(ResultCode.OTHER.getCode(),
                        StringUtils.isNotBlank(message) ? message : "服务调用错误");
            }
            String message = throwable.getMessage();
            return new BaseRtmException(ResultCode.OTHER.getCode(),
                    StringUtils.isNotBlank(message) ? message : "服务调用错误");
        }
        return null;
    }
}